import json
import uuid
from datetime import datetime
from pathlib import Path
from typing import Dict, Any, List

class AIRuleService:
    """AI规则库构建服务 - 用于构建和管理智能审查规则"""
    
    def __init__(self):
        self.rules_dir = Path("config")
        self.rules_file = self.rules_dir / "ai_rules.json"
        self.rules_dir.mkdir(exist_ok=True)
        
    async def build_ai_rules(self, building_type: str, context: Dict[str, Any] = None) -> Dict[str, Any]:
        """基于建筑类型和上下文构建AI规则库"""
        
        # 基础规则模板
        base_rules = self._get_base_rules(building_type)
        
        # 根据上下文优化规则
        if context:
            optimized_rules = self._optimize_rules_for_context(base_rules, context)
        else:
            optimized_rules = base_rules
            
        # 生成规则ID和元数据
        rule_set = {
            "rule_set_id": str(uuid.uuid4())[:8],
            "building_type": building_type,
            "created_at": datetime.now().isoformat(),
            "total_rules": len(optimized_rules),
            "rules": optimized_rules,
            "metadata": {
                "context_used": bool(context),
                "optimization_level": "enhanced" if context else "standard",
                "source": "AI规则引擎"
            }
        }
        
        # 保存规则集
        await self._save_rules(rule_set)
        
        return rule_set
    
    def _get_base_rules(self, building_type: str) -> List[Dict[str, Any]]:
        """获取基础规则模板"""
        
        common_rules = [
            {
                "rule_id": "fire_door_width",
                "category": "消防安全",
                "title": "防火门净宽度检查",
                "description": "疏散门净宽度不应小于1.4米",
                "condition": "element.Type == 'IfcDoor' AND element.IsFireExit == True",
                "threshold": 1.4,
                "unit": "m",
                "severity": "严重",
                "standard": "GB 50016-2014 建筑设计防火规范",
                "suggested_fix": "扩大门洞宽度或更换更大尺寸防火门"
            },
            {
                "rule_id": "stair_width",
                "category": "消防安全",
                "title": "疏散楼梯宽度检查",
                "description": "疏散楼梯最小净宽度不应小于1.1米",
                "condition": "element.Type == 'IfcStair' AND element.IsEscapeRoute == True",
                "threshold": 1.1,
                "unit": "m",
                "severity": "严重",
                "standard": "GB 50016-2014 建筑设计防火规范",
                "suggested_fix": "扩大楼梯间宽度或增加疏散楼梯数量"
            },
            {
                "rule_id": "corridor_width",
                "category": "消防安全",
                "title": "疏散走道宽度检查",
                "description": "疏散走道净宽度不应小于1.4米",
                "condition": "element.Type == 'IfcSpace' AND element.IsCorridor == True",
                "threshold": 1.4,
                "unit": "m",
                "severity": "严重",
                "standard": "GB 50016-2014 建筑设计防火规范",
                "suggested_fix": "扩大走道宽度或调整空间布局"
            }
        ]
        
        # 根据建筑类型添加特定规则
        type_specific_rules = self._get_type_specific_rules(building_type)
        
        return common_rules + type_specific_rules
    
    def _get_type_specific_rules(self, building_type: str) -> List[Dict[str, Any]]:
        """获取建筑类型特定规则"""
        
        if building_type == "residential":
            return [
                {
                    "rule_id": "balcony_height",
                    "category": "安全防护",
                    "title": "阳台栏杆高度检查",
                    "description": "住宅阳台栏杆高度不应低于1.05米",
                    "condition": "element.Type == 'IfcRailing' AND element.IsBalconyRailing == True",
                    "threshold": 1.05,
                    "unit": "m",
                    "severity": "严重",
                    "standard": "GB 50352-2019 民用建筑设计统一标准",
                    "suggested_fix": "加高阳台栏杆至规范要求高度"
                },
                {
                    "rule_id": "bedroom_area",
                    "category": "功能空间",
                    "title": "卧室最小面积检查",
                    "description": "双人卧室使用面积不应小于9平方米",
                    "condition": "element.Type == 'IfcSpace' AND element.RoomType == 'Bedroom'",
                    "threshold": 9,
                    "unit": "m²",
                    "severity": "中等",
                    "standard": "GB 50096-2011 住宅设计规范",
                    "suggested_fix": "调整卧室尺寸或重新规划空间"
                }
            ]
        elif building_type == "commercial":
            return [
                {
                    "rule_id": "office_height",
                    "category": "功能空间",
                    "title": "办公室净高检查",
                    "description": "办公室净高不应低于2.6米",
                    "condition": "element.Type == 'IfcSpace' AND element.RoomType == 'Office'",
                    "threshold": 2.6,
                    "unit": "m",
                    "severity": "中等",
                    "standard": "JGJ 67-2006 办公建筑设计规范",
                    "suggested_fix": "提高楼层高度或减少吊顶厚度"
                },
                {
                    "rule_id": "meeting_room_area",
                    "category": "功能空间",
                    "title": "会议室最小面积检查",
                    "description": "小型会议室使用面积不应小于12平方米",
                    "condition": "element.Type == 'IfcSpace' AND element.RoomType == 'MeetingRoom'",
                    "threshold": 12,
                    "unit": "m²",
                    "severity": "轻微",
                    "standard": "JGJ 67-2006 办公建筑设计规范",
                    "suggested_fix": "扩大会议室面积或重新规划空间"
                }
            ]
        elif building_type == "industrial":
            return [
                {
                    "rule_id": "workshop_height",
                    "category": "功能空间",
                    "title": "厂房净高检查",
                    "description": "厂房净高不应低于3.0米",
                    "condition": "element.Type == 'IfcSpace' AND element.RoomType == 'Workshop'",
                    "threshold": 3.0,
                    "unit": "m",
                    "severity": "中等",
                    "standard": "GB 50037-2013 建筑地面设计规范",
                    "suggested_fix": "提高厂房高度"
                },
                {
                    "rule_id": "fire_compartment",
                    "category": "消防安全",
                    "title": "防火分区面积检查",
                    "description": "丙类厂房防火分区最大允许建筑面积不应大于4000平方米",
                    "condition": "element.Type == 'IfcSpace' AND element.FireCompartment == True",
                    "threshold": 4000,
                    "unit": "m²",
                    "severity": "严重",
                    "standard": "GB 50016-2014 建筑设计防火规范",
                    "suggested_fix": "增加防火墙或防火卷帘划分防火分区"
                }
            ]
        
        return []
    
    def _optimize_rules_for_context(self, rules: List[Dict[str, Any]], context: Dict[str, Any]) -> List[Dict[str, Any]]:
        """根据上下文优化规则参数"""
        
        # 获取项目特定信息
        building_height = context.get("building_height", 0)
        total_area = context.get("total_area", 0)
        occupancy = context.get("occupancy", "standard")
        
        optimized_rules = []
        
        for rule in rules:
            optimized_rule = rule.copy()
            
            # 根据建筑高度调整规则
            if building_height > 24:  # 高层建筑
                if "fire" in rule["rule_id"]:
                    optimized_rule["severity"] = "严重"
                    optimized_rule["threshold"] = max(rule["threshold"] * 1.2, rule["threshold"])
            
            # 根据面积调整规则
            if total_area > 10000:  # 大型建筑
                if "area" in rule["rule_id"]:
                    optimized_rule["severity"] = "中等"
            
            # 根据使用性质调整规则
            if occupancy == "high_density":
                if "width" in rule["rule_id"] or "area" in rule["rule_id"]:
                    optimized_rule["threshold"] = max(rule["threshold"] * 1.1, rule["threshold"])
            
            optimized_rules.append(optimized_rule)
        
        return optimized_rules
    
    async def _save_rules(self, rule_set: Dict[str, Any]):
        """保存规则集到文件"""
        try:
            # 读取现有规则
            existing_rules = []
            if self.rules_file.exists():
                with open(self.rules_file, 'r', encoding='utf-8') as f:
                    existing_rules = json.load(f)
            
            # 添加新规则集
            existing_rules.append(rule_set)
            
            # 保存更新后的规则
            with open(self.rules_file, 'w', encoding='utf-8') as f:
                json.dump(existing_rules, f, ensure_ascii=False, indent=2)
                
        except Exception as e:
            print(f"保存规则失败: {e}")
    
    async def get_rules_history(self, limit: int = 10) -> List[Dict[str, Any]]:
        """获取规则构建历史"""
        try:
            if not self.rules_file.exists():
                return []
            
            with open(self.rules_file, 'r', encoding='utf-8') as f:
                rules = json.load(f)
            
            # 按时间倒序排序
            rules.sort(key=lambda x: x["created_at"], reverse=True)
            return rules[:limit]
            
        except Exception as e:
            print(f"读取规则历史失败: {e}")
            return []
    
    async def get_rule_set(self, rule_set_id: str) -> Dict[str, Any]:
        """获取特定规则集"""
        try:
            if not self.rules_file.exists():
                raise ValueError("规则文件不存在")
            
            with open(self.rules_file, 'r', encoding='utf-8') as f:
                rules = json.load(f)
            
            for rule_set in rules:
                if rule_set["rule_set_id"] == rule_set_id:
                    return rule_set
            
            raise ValueError(f"未找到规则集: {rule_set_id}")
            
        except Exception as e:
            raise ValueError(f"获取规则集失败: {e}")


class SmartLearningService:
    """智能学习服务 - 基于用户反馈的自适应优化"""
    
    def __init__(self):
        self.feedback_file = Path("data/analytics/user_feedback.json")
        self.weights_file = Path("data/analytics/rule_weights.json")
        self._init_files()
    
    def _init_files(self):
        """初始化学习数据文件"""
        if not self.feedback_file.exists():
            self.feedback_file.parent.mkdir(parents=True, exist_ok=True)
            with open(self.feedback_file, 'w', encoding='utf-8') as f:
                json.dump([], f)
        
        if not self.weights_file.exists():
            with open(self.weights_file, 'w', encoding='utf-8') as f:
                json.dump({}, f)
    
    async def record_feedback(self, rule_id: str, feedback_type: str, user_context: Dict[str, Any] = None):
        """记录用户反馈"""
        try:
            # 读取现有反馈
            with open(self.feedback_file, 'r', encoding='utf-8') as f:
                feedback_data = json.load(f)
            
            # 添加新反馈
            feedback_record = {
                "rule_id": rule_id,
                "feedback_type": feedback_type,  # "useful", "false_positive", "missed_issue"
                "timestamp": datetime.now().isoformat(),
                "user_context": user_context or {}
            }
            
            feedback_data.append(feedback_record)
            
            # 保存反馈
            with open(self.feedback_file, 'w', encoding='utf-8') as f:
                json.dump(feedback_data, f, ensure_ascii=False, indent=2)
            
            # 更新规则权重
            await self._update_rule_weights(rule_id, feedback_type)
            
        except Exception as e:
            print(f"记录反馈失败: {e}")
    
    async def _update_rule_weights(self, rule_id: str, feedback_type: str):
        """基于反馈更新规则权重"""
        try:
            with open(self.weights_file, 'r', encoding='utf-8') as f:
                weights = json.load(f)
            
            # 初始化权重
            if rule_id not in weights:
                weights[rule_id] = {"confidence": 1.0, "usage_count": 0}
            
            # 调整置信度
            if feedback_type == "useful":
                weights[rule_id]["confidence"] = min(weights[rule_id]["confidence"] * 1.1, 2.0)
            elif feedback_type == "false_positive":
                weights[rule_id]["confidence"] = max(weights[rule_id]["confidence"] * 0.8, 0.1)
            
            weights[rule_id]["usage_count"] += 1
            
            # 保存权重
            with open(self.weights_file, 'w', encoding='utf-8') as f:
                json.dump(weights, f, ensure_ascii=False, indent=2)
                
        except Exception as e:
            print(f"更新权重失败: {e}")
    
    async def get_personalized_rules(self, base_rules: List[Dict[str, Any]], user_expertise: str = "intermediate") -> List[Dict[str, Any]]:
        """根据用户专业水平返回个性化规则"""
        try:
            with open(self.weights_file, 'r', encoding='utf-8') as f:
                weights = json.load(f)
            
            personalized_rules = []
            
            for rule in base_rules:
                personalized_rule = rule.copy()
                rule_id = rule.get("rule_id", "")
                
                # 应用权重
                if rule_id in weights:
                    confidence = weights[rule_id]["confidence"]
                    if confidence < 0.5:
                        continue  # 跳过低置信度规则
                
                # 根据用户专业水平调整
                if user_expertise == "beginner":
                    personalized_rule = self._add_detailed_explanation(personalized_rule)
                elif user_expertise == "expert":
                    personalized_rule = self._simplify_rule(personalized_rule)
                
                personalized_rules.append(personalized_rule)
            
            return personalized_rules
            
        except Exception as e:
            print(f"个性化规则生成失败: {e}")
            return base_rules
    
    def _add_detailed_explanation(self, rule: Dict[str, Any]) -> Dict[str, Any]:
        """为新手用户添加详细解释"""
        enhanced_rule = rule.copy()
        enhanced_rule["explanation"] = {
            "why_it_matters": self._get_why_explanation(rule),
            "how_to_fix": self._get_fix_steps(rule),
            "visual_guide": self._get_visual_hint(rule)
        }
        return enhanced_rule
    
    def _simplify_rule(self, rule: Dict[str, Any]) -> Dict[str, Any]:
        """为专家用户简化规则"""
        simplified_rule = rule.copy()
        simplified_rule["quick_summary"] = f"{rule['title']}: {rule['threshold']}{rule['unit']}"
        return simplified_rule
    
    def _get_why_explanation(self, rule: Dict[str, Any]) -> str:
        """解释规则重要性"""
        category_map = {
            "消防安全": "关系到生命安全，确保紧急疏散",
            "安全防护": "防止意外坠落，保障人身安全",
            "功能空间": "确保空间实用性，避免使用不便"
        }
        return category_map.get(rule.get("category", ""), "符合国家标准要求")
    
    def _get_fix_steps(self, rule: Dict[str, Any]) -> List[str]:
        """提供修复步骤"""
        title = rule.get("title", "")
        
        if "门" in title:
            return [
                "1. 测量现有尺寸",
                "2. 扩大开口至规范要求",
                "3. 选择符合要求的新门",
                "4. 验证安装效果"
            ]
        elif "楼梯" in title:
            return [
                "1. 检查楼梯宽度",
                "2. 调整楼梯间尺寸",
                "3. 考虑增加楼梯数量",
                "4. 重新计算疏散能力"
            ]
        else:
            return [
                "1. 测量相关尺寸",
                "2. 对比规范要求",
                "3. 调整设计参数",
                "4. 重新验证合规性"
            ]
    
    def _get_visual_hint(self, rule: Dict[str, Any]) -> str:
        """提供可视化提示"""
        return f"检查{rule.get('title', '')}，确保≥{rule.get('threshold', '')}{rule.get('unit', '')}"
    
    async def get_learning_insights(self) -> Dict[str, Any]:
        """获取学习洞察报告"""
        try:
            with open(self.feedback_file, 'r', encoding='utf-8') as f:
                feedback_data = json.load(f)
            
            with open(self.weights_file, 'r', encoding='utf-8') as f:
                weights = json.load(f)
            
            # 分析反馈数据
            useful_count = sum(1 for f in feedback_data if f["feedback_type"] == "useful")
            false_positive_count = sum(1 for f in feedback_data if f["feedback_type"] == "false_positive")
            
            total_feedback = len(feedback_data)
            accuracy_rate = useful_count / total_feedback * 100 if total_feedback > 0 else 0
            
            return {
                "total_feedback": total_feedback,
                "accuracy_rate": round(accuracy_rate, 2),
                "useful_rules": useful_count,
                "false_positives": false_positive_count,
                "top_performing_rules": self._get_top_rules(weights, 5),
                "improvement_suggestions": self._generate_suggestions(weights)
            }
            
        except Exception as e:
            return {"error": str(e)}
    
    def _get_top_rules(self, weights: Dict[str, Any], limit: int) -> List[Dict[str, Any]]:
        """获取表现最好的规则"""
        sorted_rules = sorted(
            weights.items(),
            key=lambda x: (x[1]["confidence"], x[1]["usage_count"]),
            reverse=True
        )
        return [{"rule_id": k, **v} for k, v in sorted_rules[:limit]]
    
    def _generate_suggestions(self, weights: Dict[str, Any]) -> List[str]:
        """生成改进建议"""
        suggestions = []
        
        for rule_id, data in weights.items():
            if data["confidence"] < 0.5:
                suggestions.append(f"考虑调整规则 {rule_id} 的触发条件")
            elif data["usage_count"] < 5:
                suggestions.append(f"增加规则 {rule_id} 的测试场景")
        
        return suggestions